//转化成虚拟DOM
const h = (tag, props, children) => {
  return {
    tag,
    props,
    children,
  };
};

//递归挂载
const mount = (vnode, container) => {
  // vnode ->element
  //1.创建出真实DOM，并在vnode上保留el
  const el = (vnode.el = document.createElement(vnode.tag));
  //2.处理props
  if (vnode.props) {
    for (const key in vnode.props) {
      const value = vnode.props[key];
      //对事件监听的判断
      if (key.startsWith("on")) {
        el.addEventListener(key.slice(2).toLowerCase(), value);
      }
      el.setAttribute(key, value);
    }
  }

  //3. 处理children
  if (vnode.children) {
    if (typeof vnode.children === "string") {
      el.textContent = vnode.children;
    } else {
      vnode.children.forEach((item) => {
        mount(item, el);
      });
    }
  }

  //4.将el挂载到container中
  container.appendChild(el);
};

const patch = (n1, n2) => {
  //判断两个元素的类型
  if (n1.tag !== n2.tag) {
    //如果节点的类型不相同则没有比较的必要，那么可以直接移除n1,挂载n2
    const n1ElParent = n1.el.parentElement;
    n1ElParent.removeChild(n1.el);
    mount(n2, n1ElParent);
  } else {
    // 1. 取出element对象，并且在n2中进行保存
    const el = (n2.el = n1.el);

    //2.处理props
    const oldProps = n1.props || {};
    const newProps = n2.props || {};
    //2.1获取所有newProps添加到el
    for (const key in newProps) {
      const oldValue = oldProps[key];
      const newValue = newProps[key];
      if (newValue !== oldValue) {
        if (key.startsWith("on")) {
          //对事件监听的判断
          el.addEventListener(key.slice(2).toLowerCase(), newValue);
        } else {
          el.setAttribute(key, newValue);
        }
      }
    }
    //2.2删除旧的props
    for (const key in oldProps) {
      //如果旧属性名称没有在新属性名称中出现，则删除旧的属性
      if (!(key in newProps)) {
        if (key.startsWith("on")) {
          const value = oldProps[key];
          el.removeEventListener(key.slice(2).toLowerCase(), value);
        } else {
          el.removeAttribute(key);
        }
      }
    }

    //3.处理children
    const oldChildren = n1.children || [];
    const newChildren = n2.children || [];

    if (typeof newChildren === "string") {
      //边界判断
      if (typeof oldChildren === "string") {
        if (newChildren !== oldChildren) {
          el.textContent = newChildren;
        }
      } else {
        el.innerHTML = newChildren;
      }
    } else {
      //newChildren是一个数组
      if (typeof oldChildren === "string") {
        //oldChildren是个字符串
        el.innerHTML = "";
        newChildren.forEach((item) => {
          mount(item, el);
        });
      } else {
        // oldChildren和newChildren都不是string

        //以最短方式再进行比对替换操作 (长度相等的情况下)
        const commonLength = Math.min(oldChildren.length, newChildren.length);
        //因为递归调用，倒置oldChildren
        oldChildren.reverse();
        for (let i = 0; i < commonLength; i++) {
          patch(oldChildren[i], newChildren[i]);
        }
        //newChildren.length > oldChildren.length
        //把newCildren中比oldChildren多出来的部分直接挂载到el上
        if (newChildren.length > oldChildren.length) {
          newChildren.slice(oldChildren.length).forEach((item) => {
            mount(item, el);
          });
        }
        //newChildren.length < oldChildren.length
        //新节点数组长度小于旧节点数组长度，需要移除旧节点数组中的中的部分节点
        if (newChildren.length < oldChildren.length) {
          oldChildren.slice(newChildren.length).forEach((item) => {
            el.removeChild(item.el);
          });
        }
      }
    }
  }
};
